﻿using Cuofrisp.Core;
using Cuofrisp.Core.ParallelCore.Interfaces;
using Cuofrisp.Core.ParallelCore.Tools;
using MathNet.Symbolics;

namespace Cuofrisp.Console.MetricInverseProviders
{
    internal sealed class GivenMetricInverseProvider : IMetricInverseProvider
    {
        private readonly SymbolicExpression[,] metricInverse;
        public GivenMetricInverseProvider(SymbolicExpression[,] metricInverse)
        {
            this.metricInverse = metricInverse;
        }

        public static GivenMetricInverseProvider LoadInverse(StreamReader reader)
        {
            var firstLine = reader.ReadLine()!.Split("\t", StringSplitOptions.RemoveEmptyEntries);
            var size = firstLine.Length;

            var metricInverse = new SymbolicExpression[size, size];
            for (int i = 0; i < size; i++)
            {
                var thisLine = i == 0 ? firstLine :
                    reader.ReadLine()!.Split("\t", StringSplitOptions.RemoveEmptyEntries);
                for (int j = 0; j < size; j++)
                    metricInverse[i, j] = SymbolicExpression.Parse(thisLine[j]);
            }

            return new GivenMetricInverseProvider(metricInverse);
        }

        public void TrySetMetricInverse(
            CuofrispResult result, IExpressionSimplifier simplifier, out bool isNotFullRank)
        {
            _ = Parallel.For(0, result.MetricInverse.Length,
                new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount },
                (iJ) => {
                    var (i, j) = iJ.As2dIndex(result.VariableCount);
                    result.MetricInverse[i, j] = simplifier.Simplify(this.metricInverse[i, j]);
                });
            isNotFullRank = false;
        }
    }
}
